home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / modelers / geomview / source.lha / Geomview / tools / lisp2c < prev    next >
Text File  |  1993-11-10  |  8KB  |  287 lines

  1. #! /bin/sh
  2.  
  3. ########################################################################
  4.  
  5. # usage: lisp2c [-cprefix prefix] -o OUTFILE [ FILE1 ... ]
  6. #
  7. # writes OUTFILE.c and OUTFILE.h, if results would differ from
  8. # existing files of those names.
  9. #
  10. # If -cprefix is specified, uses "prefix_" as the prefix for C
  11. # function names.  Default prefix is "l_".
  12. #
  13. #  This script scans the input files, or standard input if no input
  14. #  files are specified, generating a C interface to each lisp function
  15. #  defined via the "DEFINE" and "LDECLARE" macros (defined in
  16. #  geomview's "lispext.h" file).  It assumes usage of the following
  17. #  form in the input files:
  18. #  
  19. #    DEFINE(name, ltype,
  20. #        docstring)
  21. #    {
  22. #      <local variable declarations and initializations>
  23. #      LDECLARE(("lname", LBEGIN,
  24. #            <argspec>,
  25. #            ...,
  26. #            LEND));
  27. #       ...
  28. #      return L...;
  29. #    }
  30. #  
  31. #  Specifically:
  32. #  
  33. #
  34. #  1. The first line of the call to DEFINE must contain exactly, in
  35. #     this order:
  36. #      1.1. the word DEFINE
  37. #      1.2. a left paren
  38. #      1.3. a name which is a valid C identifier.  There must be no
  39. #          spaces between the left paren and the name. This name with
  40. #          an "L" prepended becomes the name of the low-level C
  41. #          procedure (the one whose body follows the DEFINE call),
  42. #          and with a "l_" prepended becomes the name of the C
  43. #          interface to the corresponding lisp function (unless an
  44. #          alternate prefix is specified with the -cprefix argument
  45. #          to this script).
  46. #      1.4  a comma (possibly preceeded and/or followed by spaces or
  47. #        tabs)
  48. #      1.5  a lisp type name (like LINT or LGEOM etc) which indicates
  49. #        the type of the lisp object returned by this function.
  50. #      1.6  a comma (possibly preceeded and/or followed by spaces or
  51. #        tabs)
  52. #  
  53. #  2. The rest of the DEFINE call consists of the docstring argument,
  54. #     which must be a single string and may be broken over any number
  55. #     of lines.
  56. #
  57. #  
  58. #  3. The first line of the call to LDECLARE must contain, in this order:
  59. #      1.1. the word LDECLARE
  60. #      1.2. two left parens
  61. #      1.3. a string which becomes the lisp name of the function
  62. #      1.4  a comma (possibly preceeded and/or followed by spaces or
  63. #        tabs)
  64. #      1.5  the word LBEGIN
  65. #      1.6  a comma (possibly preceeded and/or followed by spaces or
  66. #        tabs)
  67. #  
  68. #  4. Intermediate lines of the LDECLARE call must contain one
  69. #     <argspec> per line; where <argspec> is either the word LOPTIONAL
  70. #     or something with the syntax
  71. #  
  72. #      [ modifier, ] ltype, address
  73. #  
  74. #     where modifier is one of LHOLD or LLITERAL, ltype is a lisp type
  75. #     name, and address is the address of a local variable into which
  76. #     the corresponding argument's value is to be loaded.  Any
  77. #     arguments following LOPTIONAL are taken to be optional.
  78. #
  79. #  5. The last line of the LDECLARE call must contain just the string
  80. #     "LEND));" possibly preceeded by spaces or tabs.
  81. #
  82. # This script generates the C interface (consisting of the function
  83. # declaration in OUTFILE.h and the function itself in OUTFILE.c) only
  84. # for functions which use both the DEFINE and LDECLARE macros.  To
  85. # prevent the generation of a C interface for a particular function,
  86. # preceed the word LDECLARE by a comment on the same line, as in:
  87. #
  88. #     /*NOC*/ LDECLARE(("foo, LBEGIN,
  89. # The contents of the comment are irrelvant; its purpose is simply
  90. # to arrange that LDECLARE is not the first thing on its line.
  91.  
  92. cprefix="l_" ;
  93. outfile=""
  94.  
  95. while : ; do
  96.  
  97.   case $1 in
  98.     -cprefix)
  99.     cprefix=$2 ;
  100.     shift 2 ;
  101.     ;;
  102.     -o)
  103.     outfile=$2 ;
  104.     outstem=`basename $outfile`
  105.     shift 2 ;
  106.     ;;
  107.     *)
  108.     break ;
  109.     ;;
  110.   esac
  111.  
  112. done
  113.  
  114. cfile=/tmp/lisp2c.out.c
  115. hfile=/tmp/lisp2c.out.h
  116.  
  117. /bin/rm -f $cfile $hfile
  118.  
  119. # start with an empty .h file in case the awk script below doesn't
  120. # output anything to it:
  121. touch $hfile
  122.  
  123. cat $* |
  124.  
  125. # first turn all parens, semicolons, and commas into spaces
  126. tr '();,' '    ' |
  127.  
  128. # now let awk do its thing
  129. awk '
  130. BEGIN { cprefix="'$cprefix'" ;
  131.     outfile="'$outfile'" ;
  132.     outstem="'$outstem'" ;
  133.     hfile="'$hfile'" ;
  134.     fcount = 0 ;
  135.     inldeclare=0 ;
  136.     type["LINT"]    = "int" ;
  137.     type["LFLOAT"]    = "float" ;
  138.     type["LSTRING"]    = "char *" ;
  139.     type["LLIST"]    = "LList  *" ;
  140.     type["LLOBJECT"]    = "LObject *" ;
  141.     type["LID"]            = "int" ;
  142.     type["LKEYWORD"]    = "int" ;
  143.     type["LSTRINGS"]    = "char *" ;
  144.     type["LGEOM"]    = "GeomStruct *" ;
  145.     type["LCAMERA"]    = "CameraStruct *" ;
  146.     type["LWINDOW"]    = "WindowStruct *" ;
  147.     type["LAP"]        = "ApStruct *" ;
  148.     type["LTRANSFORM"]  = "TransformStruct *" ;
  149.     type["LTRANSFORMN"] = "TmNStruct *" ;
  150.     type["LVOID"]       = "void" ;
  151.     type["LREST"]    = "LList *" ;
  152.     }
  153. $1 == "LDEFINE" {
  154.     fstem = $2 ;        # stem from which function names are built
  155.     ftype = $3 ;        # functions return type
  156.     next ;
  157.     }
  158. $1 == "LDECLARE" {
  159.     name = substr($2,2,length($2)-2) ;    # lisp function name
  160.     inldeclare=1 ;
  161.     lakearg = 0;
  162.     argc = 0 ;
  163.     next
  164.     }
  165. $NF == "LEND" || atend == 1 {
  166.     if (inldeclare) {
  167.     # remember data for this function
  168.     ++fcount;
  169.     cname = cprefix fstem ;
  170.     fstems[fcount] = fstem ;
  171.     cnames[fcount] = cname ;
  172.     names[fcount] = name ;
  173.     # build the declaration
  174.     dec = sprintf "%s %s(", type[ftype], cname ;
  175.     for (i=1; i<=argc; ++i) {
  176.         if (i>1) dec = dec sprintf ", " ;
  177.         if (arg[i] == "LARRAY") {
  178.         dec = dec sprintf "%s *a%1d, int a%1dn", type[basetype[i]], i, i ;
  179.         } else {
  180.         if (type[arg[i]] != "") dec = dec sprintf "%s ", type[arg[i]] ;
  181.         else dec = dec sprintf "??? " ;
  182.         dec = dec sprintf "a%1d", i ;
  183.         }
  184.     }
  185.     dec = dec sprintf ")" ;
  186.     # print the declaration, possibly also in header file
  187.     printf "%s\n", dec ;
  188.     if (outfile != "") printf "%s;\n", dec > hfile ;
  189.     # print the function body
  190.     printf "{\n" ;
  191.     printf "  LObject *val = LEvalFunc(\"%s\",\n", name ;
  192.     for (i=1; i<=argc; ++i) {
  193.         if (arg[i] == "LARRAY") {
  194.         printf "\t\t\t   LARRAY, %s, a%1d, a%1dn,\n", basetype[i], i, i ;
  195.         } else {
  196.         printf "\t\t\t   %s, a%1d,\n", arg[i], i ;
  197.         }
  198.     }
  199.     printf "\t\t\t   LEND);\n"
  200.     if (type[ftype] != "void") {
  201.         printf "  %s retval;\n", type[ftype] ;
  202.         printf "  LFROMOBJ(%s)(val, &retval);\n", ftype ;
  203.     }
  204.     printf "  LFree(val);\n"
  205.     if (type[ftype] != "void") printf "  return retval;\n"
  206.     printf "}\n\n"
  207.     inldeclare=0 ;
  208.     atend = 0;
  209.     next
  210.     }
  211.     }
  212. { if (inldeclare) {
  213.     i = 1;
  214.     while (i <= NF) {
  215.     if ($i == "LLAKE") {
  216.         lakearg = 1; next;
  217.     } else if ($i == "LOPTIONAL") {
  218.         ++i; continue;
  219.     } else if ($i == "LHOLD") {
  220.         ++i; continue;
  221.     } else if ($i == "LLITERAL") {
  222.         ++i; continue;
  223.     } else if ($i == "LARRAY") {
  224.         ++i;
  225.         ++argc ;
  226.         arg[argc] = "LARRAY";
  227.         basetype[argc] = $i;
  228.         next;
  229.     } else if ($i == "LREST") {
  230.         ++argc;
  231.         arg[argc] = $i ;
  232.         atend = 1;
  233.         next ;
  234.     } else {
  235.         ++argc ;
  236.         arg[argc] = $i ;
  237.         next ;
  238.     }
  239.     }
  240.   }
  241. }
  242. END {
  243.     printf "\n" ;
  244.     for (i=1; i<=fcount; ++i) {
  245.     printf "extern LObject *L%s(Lake *, LList *);\n", fstems[i] ;
  246.     }
  247.     printf "\n" ;
  248.     for (i=1; i<=fcount; ++i) {
  249.     printf "extern char H%s[];\n", fstems[i] ;
  250.     }
  251.     printf "\n" ;
  252.     printf "\nvoid %s_init()\n{\n", outstem ;
  253.     for (i=1; i<=fcount; ++i) {
  254.     printf "  LDefun(\"%s\", L%s, H%s);\n", names[i], fstems[i], fstems[i] ;
  255.     }
  256.     printf "}\n\n" ;
  257. }
  258. ' |
  259.  
  260. # and send output to "outfile.c" if -o specified, otherwise
  261. # to standard output
  262. if [ "$outfile" != "" ] ; then
  263.   cat > $cfile ;
  264.  
  265.   if [ -f $cfile ] && cmp $cfile $outfile.c 1>&- 2>&- ; then
  266.     : # no change to $outfile.c
  267.   else
  268.     /bin/rm -f $outfile.c ;
  269.     /bin/mv $cfile $outfile.c
  270.     echo $outfile.c
  271.   fi
  272.  
  273.   if [ -f $hfile ] && cmp $hfile $outfile.h 1>&- 2>&- ; then
  274.     : # no change to $outfile.h
  275.   else
  276.     /bin/rm -f $outfile.h ;
  277.     /bin/mv $hfile $outfile.h
  278.     echo $outfile.h
  279.   fi
  280. else
  281.   cat ;
  282. fi
  283.  
  284. /bin/rm -f $cfile $hfile
  285.